package generator.gridgain;

import java.util.ArrayList;
import java.util.List;

import generator.utils.java2xml.DocumentModifier;

import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
 * Esta clase es la encargada de la transformación de una clase con convenciones JGRIM en otra clase cuyo nombre será igual al original más el sufijo "Peer" que hace uso del soporte brindado por el middleware GridGain. Dicha transformación se dará cuando      {@link GridGainGridifier}      invoque al método build().
 */
public class PeerClassBuilder extends DocumentModifier implements Buildable{
	
	
	private final String GRIDFACTORY_PACKAGE = 		"org.gridgain.grid.GridFactory";


	private final String GRIDEXCEPTION_PACKAGE = 	"org.gridgain.grid.GridException";


	private final String CONCURRENTFUTURE_PACKAGE = "java.util.concurrent.Future";


	private final String EXECUTORSERVICE_PACKAGE =  "java.util.concurrent.ExecutorService";


	private String ACCESSGRIDMETHOD = null;
	
		
	/**
	 * Representa las signaturas de los métodos que se pretenden gridificar.
	 * @uml.property  name="methodsToGridify"
	 */
	protected org.w3c.dom.NodeList methodsToGridify;
	
	
	/**
	 * Documento que representa la clase que contiene los métodos a ser gridificados. Sobre ella se efectuarán transformaciones para permitir que los métodos indicados por el atributo    {@link methodToGridify}    puedan ejecutar haciendo uso del middleware GridGain.  Dicho documento es el que representa la clase con convenciones JGrim codificada por el usuario
	 * @uml.property  name="classToGridify"
	 */
	protected org.w3c.dom.Document classToGridify;
	
	
	/**Constructor vacío de la clase.
	 * NOTA: la invocación al método build() sobre la instancia retornada arrojará una <B>NullPointerException</B>
	 * si previamente a esta no se realizó el correspondiente seteo de los atributos {@link methodsToGridify} y 
	 * {@link classToGridify}*/
	public PeerClassBuilder(){
		super();
		methodsToGridify = null;
		classToGridify = null;
	}
	
	/**Constructor de la clase PeerClassBuilder
	 * @param classToGridify
	 * 			Documento que representa la clase que contiene los métodos a ser gridificados.
	 * 			Dicho documento es el que representa la clase del usuario que contiene las convenciones de gridificación JGrim.
	 * @param methodsToGridify
	 * 			Representa las signaturas de los métodos que se pretenden gridificar.
	 * */
	public PeerClassBuilder(org.w3c.dom.Document classToGridify, org.w3c.dom.NodeList methodsToGridify){
		super();
		this.classToGridify = classToGridify;
		this.methodsToGridify = methodsToGridify;
	}
	
	
	/**
	 * @return       NodeList que representa la lista de signaturas de los métodos que serán gridificados sobre la clase representada  por el atributo       {@link classToGridify}  
	 * @uml.property  name="methodsToGridify"
	 */
	public org.w3c.dom.NodeList getMethodsToGridify() {
		return methodsToGridify;
	}
	
	/**
	 * Setea la lista de siganturas de métodos que serán gridificados. NOTA: las mismas deberán pertenecer a métodos contenidos en la clase a gridificar representada por el atributo       {@link classToGridify}      .
	 * @param methodsToGridify       lista de signaturas de métodos que se pretenden gridificar
	 * @uml.property  name="methodsToGridify"
	 */
	public void setMethodsToGridify(NodeList methodsToGridify) {
		this.methodsToGridify = methodsToGridify;
	}

	/**
	 * @return       un org.w3c.dom.Document que representa la clase que contiene los métodos a ser gridificados.   La misma será transformada en clase Peer una vez invocado el método       {@link       build()}  
	 * @uml.property  name="classToGridify"
	 */
	public org.w3c.dom.Document getClassToGridify() {
		return classToGridify;
	}

	/**
	 * Setea la clase que contiene los métodos a ser gridificados y que será transformada en clase Peer en la invocación al método       {@link       build()}      .
	 * @param classToGridify       documento que representa la clase java con convenciones JGrim
	 * @uml.property  name="classToGridify"
	 */
	public void setClassToGridify(org.w3c.dom.Document classToGridify) {
		this.classToGridify = classToGridify;
	}
	
	/**Permite agregar a la clase Peer el método que será empleado para obtener el
	 * {@link java.util.concurrent.ExecutorService}, que permitirá la distribución de los trabajos generados*/
	protected void addExecutorServiceGetter(){
    	try{
		Element executorServiceMethod = (Element)xpath.evaluate("//structure[@id=\"exServGetter\"]/"+METHOD, preBuildStructures, XPathConstants.NODE);		
    	Element executorServiceMethodAdopted = (Element)classToGridify.importNode(executorServiceMethod, true);
    	Element classDeclaration = (Element)xpath.evaluate("//"+CLASS, classToGridify, XPathConstants.NODE);
    	classDeclaration.appendChild(executorServiceMethodAdopted);
    	}catch (Exception e){
    		System.out.println("Falló inserción de método getExecutorService() a clase Peer");
    	}
    	
	
    }
			
	
	/**Este método efectua el tratamiento de una sentencia Selfdependency, es decir, efectua los cambios necesarios
	 * en la clase peer para permitir la generación de un trabajo a partir del método a gridificar y su distribución
	 * por los nodos de un grid con el soporte del middleware de gridificación GridGain.
	 * @param selfDependencyCall
	 * 			es el nodo extraido del código de la clase a gridificar que representa un llamado a
	 * 			la función getSelfDependency() (junto al método gridificable que se invoca). En otras
	 * 			palabras, dicho nodo contiene toda la información generada a partir de una sentencia
	 * 			del estilo: getSelfDependency().metodoAGridificar(param1, param2,..,paramN);   
	 * 			 */
	protected void gridEnableSelfDependencyCall(Node selfDependencyCall){
				
		Element assignmentSentence = (Element)selfDependencyCall.getParentNode();		
		Element declare = this.getDeclaration(assignmentSentence);
		Element ambitoVar = (Element)declare.getParentNode();		
		this.setFutureUses(ambitoVar,assignmentSentence);		
		Element newAssig = this.setFutureDeclaration(declare,assignmentSentence);
		this.setSubmitJob(newAssig);
				
	}

	/**Setea la correspondiente declaración y cambio de nombre de la variable contenida en el elemento <B>declare</B>
	 * Luego de la invocación, el tipo de la variable pasará a ser un objeto Future&lt&claseAgrdificar_metodoAgridificar_GERgt 
	 * Por su parte el nombre de la misma pasará a ser future_nombreVariable
	 * @param declare
	 * 			Elemento que representa la declaración de la variable. Se espera algo de la forma &ltlocal-variable&gt
	 * @param assignment
	 * 			Elemento que representa una sentencia de asignación en la que se emplea la convención JGrim para acceder
	 * 			a métodos gridificables de una clase, es decir, es el nodo que representa a
	 * 			x = getSelfDependency().metodoAgridificar(param1, para2,..,paramN), donde x es el nombre de la variable
	 * 			contenida en <B>declare</B>. Este parámetro es empleado para armar el tipo de la variable</BR>
	 * NOTA: el documento la que pertenece <B>assignment</B> y por lo tanto <B>declare</B> se ve modificado luego
	 * de la invocación*/
	protected Element setFutureDeclaration(Element declare, Element assignment){		

		Element retorno = assignment;
		try {//levanto una declaración genérica, y le agrego el hijo de la declaración original que corresponde al valor de la variable							 
			Element futureDec = (Element)xpath.evaluate("//structure[@id=\"localVarDec\"]/"+LOCALVARIABLE, preBuildStructures, XPathConstants.NODE);
			Element nodeToAdd = (Element)declare.getOwnerDocument().importNode(futureDec, true);
			
			//obtengo el valor que se asigna junto con la declaración de la variable
			Element value = (Element)declare.getChildNodes().item(1);
			if (value != null){//si la variable tiene asignado un valor en su declaración, entonces el valor contiene un llamado a getSelfDependency
				nodeToAdd.appendChild(value);
				retorno = nodeToAdd;
			}				
			Element oldChild = (Element)declare.getParentNode().replaceChild(nodeToAdd, declare);			
			//efectuo el correspondiente cambio de nombres
			nodeToAdd.setAttribute("name", "future_"+oldChild.getAttribute("name"));		
			Element decType = (Element) nodeToAdd.getElementsByTagName(TYPE).item(FIRST);			
			decType.setAttribute("name", "Future<"+this.getNameGE(retorno)+"R>");			
			
		} catch (XPathExpressionException e) {			
			e.printStackTrace();
		}
		return retorno;		
	}
		
	/**convierte una sentencia de asignación del estilo: x = getSelfDependency().metodoAgridificar(param1, para2,..,paramN)
	 * a una sentencia de a partir de la cual se crea un trabajo con el método a gridificar y se lo envía a ejecutar al
	 * grid de GridGain.
	 * @param assignmentSentence
	 * 			Elemento que representa una sentencia de asignación en la que se emplea la convención JGrim para acceder
	 * 			a métodos gridificables de una clase, es decir, es el nodo que representa a
	 * 			x = getSelfDependency().metodoAgridificar(param1, para2,..,paramN)</BR>
	 * NOTA: el documento la que pertenece <B>assignmentSentence</B> se ve modificado luego de la invocación
	 */
	private void setSubmitJob(Element assignmentSentence) {
		
		try {
			//si en la sentencia de asignación no viene incluida la declaracion de la variable future, le actualizo
			//el nombre a esta para que se corresponda con el de la declaración del future.
			if (assignmentSentence.getNodeName().compareTo(LOCALVARIABLE) != EQUAL){			
				Element varRef = (Element)xpath.evaluate(ASSIGLEFTVALUE+"/"+VARREF+"[1]", assignmentSentence, XPathConstants.NODE);
				varRef.setAttribute("name", "future_"+varRef.getAttribute("name"));
			}		
		
			this.setSubmitParam(assignmentSentence);
			
			Element submitCall = (Element)xpath.evaluate("self::*//"+METHODCALL+"["+TARGET+"/"+METHODCALL+"[@message='get"+ACCESSGRIDMETHOD+"']/"+TARGET+"/"+THIS+"]", assignmentSentence, XPathConstants.NODE);
			submitCall.setAttribute("message", "submit");
			Element executorServiceCall = (Element)xpath.evaluate("self::*//"+METHODCALL+"[@message='get"+ACCESSGRIDMETHOD+"']", submitCall, XPathConstants.NODE);
			executorServiceCall.setAttribute("message", "getExecutorService");
			
			
			
		} catch (XPathExpressionException e) {			
			e.printStackTrace();
		}		
	}

	/**
	 * Arma y setea el parámetro del método submit, utilizado para enviar trabajos al grid
	 * @param assignmentSentence
	 * 			sentencia de asignación en la que se emplea la convención JGrim para acceder a los métodos
	 * 			gridificables de una clase, es decir, el nodo que representa a
	 * 			x = getSelfDependency().metodoAgridificar(param1, para2,..,paramN)</BR>
	 * NOTA: el documento la que pertenece <B>assignmentSentence</B> se ve modificado luego de la invocación
	 */
	private void setSubmitParam(Element assignmentSentence) {
		try {
			Element newGER = (Element)xpath.evaluate("//structure[@id=\"newGER\"]/"+ARGUMENTS, preBuildStructures, XPathConstants.NODE);			
			Element nodeToAdd = (Element)assignmentSentence.getOwnerDocument().importNode(newGER, true);
			Element typeGER = (Element)xpath.evaluate("//"+TYPE, nodeToAdd, XPathConstants.NODE);
			typeGER.setAttribute("name", this.getNameGE(assignmentSentence)+"J");
			
			Element argumentsSD = (Element)xpath.evaluate("self::*//"+METHODCALL+"["+TARGET+"/"+METHODCALL+"[@message='get"+ACCESSGRIDMETHOD+"']/"+TARGET+"/"+THIS+"]/"+ARGUMENTS, assignmentSentence, XPathConstants.NODE);
			Element argumentsEX = (Element)xpath.evaluate(NEW+"/"+ARGUMENTS,nodeToAdd,XPathConstants.NODE);
			NodeList childs = argumentsSD.getChildNodes();
			for (int i = 0; i < childs.getLength(); i++)				
				argumentsEX.appendChild(childs.item(i).cloneNode(true));				
			
			Node father = argumentsSD.getParentNode();
			father.replaceChild(nodeToAdd, argumentsSD);			
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		  }
	}
	
	
	/**
	 * Obtiene el prefijo del nombre que se les dá tanto a la clase GridExecutorResult como GridExecutorJob.   
	 * @param assignmentSentence 
	 * 			representa la sentencia en la que se hace uso de la convención JGrim para acceder a los métodos
	 * 			gridificables de una clase, es decir, el nodo que representa a 
	 * 			x = getSelfDependency().metodoAgridificar(param1, para2,..,paramN)
	 * @return el prefijo que constituye el nombre de las clases de soporte a la Clase Peer.
	 */
	private String getNameGE(Element assignmentSentence) {
		
		String gridifiableMethod="----";
		try {			
			gridifiableMethod = (String)xpath.evaluate("self::*//"+METHODCALL+"["+TARGET+"/"+METHODCALL+"[@message='get"+ACCESSGRIDMETHOD+"']/"+TARGET+"/"+THIS+"]/@message", assignmentSentence, XPathConstants.STRING);
			if (gridifiableMethod.compareTo("") == EQUAL)
				System.err.println("[ERR] la clase a ser gridificada no cumple con alguna convención JGrim");
			Element classTag = (Element)assignmentSentence.getOwnerDocument().getElementsByTagName(CLASS).item(FIRST);
			return classTag.getAttribute("name")+"_"+gridifiableMethod+"GE";
		} catch (XPathExpressionException e) {			
			e.printStackTrace();
			return gridifiableMethod;
		}		
	}	
	
	
	/**Obtiene todas las ocurrencias de la variable varName contenidas en la sentencia o estructura de
	 * control <B>sentence</B>.
	 * Se tomarán las ocurrencias que se encuentren del lado derecho de una asignación,
	 * las incluidas en parámetros de una llamada a método, las pertenecientes a una condición o a una
	 * sentencia return de un método.
	 * No tiene en cuenta las ocurrencias de la variable del lado izquierdo de una asignación ni
	 * tampoco la declaración de la misma.   
	 * @param sentence
	 * 			representa la sentencia o estructura de control donde se buscarán las ocurrencias de la variable
	 * @param varName
	 * 			el nombre de variable de la que se prentede hallar sus ocurrencias
	 * @return org.w3c.dom.NodeList que contiene nodos que responden a la estructura<BR>
	 * 			&ltvar-ref name="varName"&gt */
	private NodeList getVarUses(Element sentence, String varName){
		
		// expresion xpath: self::*//var-ref[@name='x' and not(count(ancestor::lvalue)>="1")]
		String varNameLocation = "self::*//"+VARREF+"[@name='"+varName+"' and not(count(ancestor::"+ASSIGLEFTVALUE+")>='1')]";
				
		try {
			return (NodeList)xpath.evaluate(varNameLocation, sentence, XPathConstants.NODESET);
		} catch (XPathExpressionException e) {
			System.err.println("[ERR] Falló recuperación de los usos de la variable"+varName);
			e.printStackTrace();
			return null;
		}
				
	}
	
	/**
	 * Método encargado de insertar el try catch necesario para la ejecución en el grid. El try es necesario para
	 * poder utilizar la función get() de un Future.
	 * 
	 * @param methodClass método a gridificar
	 */
	private void addTryCatch(Element methodClass) {
		try {
			//Nodo prebuild
			Element tryNode = (Element)xpath.evaluate("//structure[@id=\"tryCatch\"]/"+BODYMETHOD, preBuildStructures, XPathConstants.NODE);
			Element retStatment = (Element)tryNode.getElementsByTagName("literal-number").item(FIRST);
			retStatment.setAttribute("value", this.getReturnValue(methodClass));			
			// Block que contiene el método a gridificar
			Element methodBody = (Element)methodClass.getElementsByTagName(BODYMETHOD).item(FIRST);
			Element nodeToAdd = (Element) methodClass.getOwnerDocument().importNode(tryNode,true);
			// copiar el bloque del método dentro de la sentencia try
			Element tryBlock = (Element) nodeToAdd.getElementsByTagName("try").item(FIRST);
			Node catchBlock = tryBlock.getElementsByTagName("catch").item(FIRST);
			tryBlock.insertBefore(methodBody, catchBlock);
			methodClass.appendChild(nodeToAdd);
 		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}		
	}		
    
	/**
	 * Dado el método a gridificar, se devuelve el valor de retorno generico del método segun el tipo que retorne
	 * Para valores numericos se retorna 0, para valores boolean se retorna false, para objetos se retorna null y para 
	 * métodos void se retorna un String vacio.
	 * 
	 * @param methodClass método a gridificar
	 * @return
	 */
	private String getReturnValue(Element methodClass) {
		Element typTag = (Element)methodClass.getElementsByTagName("type").item(FIRST);
		String type	= typTag.getAttribute("name");
		String dimension = typTag.getAttribute("dimensions");
		if(this.isPrimitive(type)&& dimension.equals("")){
			if(type.equals("boolean"))
				return "false";
			else
				return "0";
		}			
		else{
			if(type.equals("void"))
				return "";
			else
				return "null";

		}
	}
	
	/**
	 * Método encargado de obtener el nombre de la variable de instancia que corresponde a la dependencia propia.
	 * Setea el valor obtenido a ACCESSGRIDMETHOD para su posterior uso.
	 */
	
	private void setSDName() {
		try {
			Document interf = this.methodsToGridify.item(FIRST).getOwnerDocument();
			String className = (String)xpath.evaluate("//"+INTERFACE+"/@name", interf, XPathConstants.STRING);
			Element typeVar= (Element)xpath.evaluate("//"+ATTRIBUTE+"/"+TYPE+"[@name=\""+className+"\"]", this.classToGridify,XPathConstants.NODE);
			Element varDeclar = (Element)typeVar.getParentNode();
			String varName = varDeclar.getAttribute("name");
			this.ACCESSGRIDMETHOD = toUpCase(varName);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}		
	}
	
	/**
	 * Dado el string pasado como parametro, devuelve el mismo string pero con 
	 * la primer letra esta en mayuscula y el resto permanecen igual.
	 * @param str string a modificar
	 * @return un nuevo string con sus palabras en title case
	 */
	private String toUpCase(String str){
		String result = "";
		for (int i = 0; i < str.length(); i++){
			String next = str.substring(i, i + 1);
			if (i == 0){
				result += next.toUpperCase();
			} else {
				result += next;
			}
		}
		return result;
	}

	
	/**Reemplaza todas la ocurrencias de la <I>variable</I> referenciada en el lado izquierdo de la asignación <B>assignSentence</B>
	 * por la variable <I>future_variable</I>, que se encuentran contenidas en el ámbito de <I>variable</I> indicado por
	 * <B>ambitoVar</B> 
	 * @param ambitoVar
	 * 			elemento que representa el ámbito de la variable, donde se buscarán las ocurrencias de dicha variable.
	 * 			NOTA: este elemento se obtiene consultando el padre del nodo que representa la declaración de una variable. 
	 * @param assignSentence
	 * 		  sentencia de asignación a partir de donde se realizarán los reemplazos que además contiene el nombre de la
	 * 		  variable que se desea reemplazar</BR>
	 * NOTA: el documento la que pertenece <B>assignmentSentence</B> y por consiguiente <B>ambitoVar</B> se ve modificado
	 * 		 luego de la invocación*/
	private void setFutureUses(Element ambitoVar, Element assignSentence){
				
		NodeList ambitoSentences = ambitoVar.getChildNodes();
		String futureName = "future_"+this.getVarNameInAssignment(assignSentence);				
		Element genericFutureGetterResult = null;
		try {
			genericFutureGetterResult = (Element)xpath.evaluate("//structure[@id=\"futureGetResult\"]/child::"+METHODCALL, preBuildStructures, XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			System.err.println("Fallo la busqueda del nodo genérico que representa el future.get().getResult()");
			e.printStackTrace();
		}			
		//me muevo hasta la sentencia próxima inmediata a la que contiene el llamado del getSelfDependecy 
		int i = 0;		
		while (i < ambitoSentences.getLength() &&
				assignSentence.compareDocumentPosition(ambitoSentences.item(i)) != Element.DOCUMENT_POSITION_FOLLOWING &&
				assignSentence.compareDocumentPosition(ambitoSentences.item(i)) != 10 //10 significa que assignSentece está contenida en ambitoSentences.item(i) 
			   )
			i+=1;			
		
		//para todas las sentencias despues del getSelfDependecy busco y reemplazo genericFutureGetterResult por la variable
		//donde se guarda el resultado de la invocación a getSelfDependency
		while (i < ambitoSentences.getLength()){
			NodeList varReferences = this.getVarUses((Element)ambitoSentences.item(i),this.getVarNameInAssignment(assignSentence));
			if (varReferences.getLength()!=0)
				for (int j = 0; j < varReferences.getLength(); j++){
					Node newNode = ambitoVar.getOwnerDocument().importNode(genericFutureGetterResult, true);					
					Element varRef = (Element)varReferences.item(j);
					Node father = varRef.getParentNode(); 
					father.replaceChild(newNode,varRef);
					
					NodeList future_anyOcurrences = this.getVarUses((Element)newNode, "future_any");
					Element future_any = (Element)future_anyOcurrences.item(FIRST);
					future_any.setAttribute("name", futureName);
				}
			
			i+=1;
		}		
	}
	
	
	/**Genera la clase Peer. La clase Peer es el resultado de la adaptación de una clase java (con convenciones JGrim) a
	 * otra clase que emplea el middleware de gridificación GridGain donde las referencias a métodos que el usuario
	 * desea gridificar, representados por el atributo {@link methodsToGridify}, se transforman en sentencias que hacen
	 * que crean y distribuyen los trabajos generados entre los nodos que pertenecen al grid. 
	 * </BR> 
	 * NOTA: es necesario que los atributos {@link classToGridify} y {@link methodsToGridify} de la instancia de
	 * PeerClassBuilder se encuentren seteados.
	 * @return org.w3c.dom.Document que representa la clase Peer
	 **/
	public org.w3c.dom.Document build(){
				
			System.out.println("************* Generando clase Peer ***************");
			
			try {
				this.setSDName();
				//se elimina el método getSelfDependecy, el método setSelfDependency y el atributo al que hacen referencia dichos métodos. (todo ello producto
				//de las convenciones JGRIM)
				Element sdGetterMethod = (Element)xpath.evaluate("//"+METHOD+"[@name='get"+ACCESSGRIDMETHOD+"']", classToGridify,XPathConstants.NODE);				
				String interfaceName = ( (Element) ( (NodeList)sdGetterMethod.getElementsByTagName(TYPE)).item(FIRST)).getAttribute("name");
				sdGetterMethod.getParentNode().removeChild(sdGetterMethod);
				Node field = (Node)xpath.evaluate("//"+ATTRIBUTE+"["+TYPE+"[@name='"+interfaceName+"']]", classToGridify,XPathConstants.NODE);
				field.getParentNode().removeChild(field);				
				Element sdSetterMethod = (Element)xpath.evaluate("//"+METHOD+"[@name='set"+ACCESSGRIDMETHOD+"']", classToGridify,XPathConstants.NODE);
				if (sdSetterMethod != null)
					sdSetterMethod.getParentNode().removeChild(sdSetterMethod);				
				
				//se agrega el método para obtener executors service
				this.addExecutorServiceGetter();
				System.out.println("[INFO] incorporación de ExecutorService getter: listo");
				
				this.addImport(EXECUTORSERVICE_PACKAGE, classToGridify);
				this.addImport(CONCURRENTFUTURE_PACKAGE, classToGridify);
				this.addImport(GRIDEXCEPTION_PACKAGE, classToGridify);
				this.addImport(GRIDFACTORY_PACKAGE, classToGridify);			
				System.out.println("[INFO] incorporación de sentencias import: listo");
										
				//acomodar expresion para que contemple el caso del llamado al método sin el "this."
				String callsLocation = new String("//"+METHODCALL+"["+TARGET+"/"+METHODCALL+"[@message=\"get"+ACCESSGRIDMETHOD+"\"]]");
				//busco todas las ocurrencias de la llamada al método getSelfDependency dentro de la clase completa. 
				NodeList methodsCalls = (NodeList)xpath.evaluate(callsLocation, classToGridify,XPathConstants.NODESET);			
				
				List<Element> methodWithSD = new ArrayList<Element>();  
				if (methodsCalls != null){
					for (int i = 0; i < methodsCalls.getLength(); i++){
						Element method= (Element) xpath.evaluate("ancestor::"+METHOD,methodsCalls.item(i),XPathConstants.NODE);
						if (!methodWithSD.contains(method))
							methodWithSD.add(method);
						this.gridEnableSelfDependencyCall(methodsCalls.item(i));												
					}						
				}
				
				for (Element element : methodWithSD) {
					this.addTryCatch(element);
				}
				System.out.println("[INFO] incorporación de sentencias de gridificación: listo");
				
				String className = (String)xpath.evaluate("//"+CLASS+"/@name", classToGridify,XPathConstants.STRING);
				this.setClassName(className+"Peer", classToGridify);
				System.out.println("[INFO] Renombrando clase a gridificar: listo");
			
			} catch (XPathExpressionException e) {
				System.err.println("[ERR] la clase a gridificar no cumple con alguna convención JGrim, chequee el uso de SelfDependency");
				e.printStackTrace();
			}
			return classToGridify;
	}	
}
